package cn.bonoon.services;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.bonoon.core.IRoleEditor;
import cn.bonoon.core.plugins.RoleService;
import cn.bonoon.entities.AccountEntity;
import cn.bonoon.entities.AccountPrivilegeEntity;
import cn.bonoon.entities.RoleAccountEntity;
import cn.bonoon.entities.RoleEntity;
import cn.bonoon.entities.RolePrivilegeEntity;
import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.menus.MenuPrivilegeReader;
import cn.bonoon.kernel.menus.MenuableDefinition;
import cn.bonoon.kernel.menus.ModuleDefinition;
import cn.bonoon.kernel.menus.ModuleManager;
import cn.bonoon.kernel.menus.TabItemDefinition;
import cn.bonoon.kernel.menus.TabsDefinition;
import cn.bonoon.kernel.support.IOperator;
import cn.bonoon.kernel.support.services.AbstractService;

@Service
@Transactional(readOnly = true)
public class RoleServiceImpl extends AbstractService<RoleEntity> implements RoleService {
	
	private final String _0 = "select x from RolePrivilegeEntity x where x.role.id=?";
	private final String _1 = "select x from RoleEntity x where x.status=1 and x.deleted=false";
	private final String _1_1 = "select x.role from RoleAccountEntity x where  x.account.id=? and x.role.deleted=false";
	private final String _2 = "select x from RoleEntity x where x.status=1 and x.deleted=false and x.ownerId=?";
	private final String _3 = "select x.role.id from RoleAccountEntity x where x.invalid=false and x.account.id=?";
	private final String _4 = "select x from RoleAccountEntity x where x.account.id=?";
	private final String _5 = "select x.meunId from RolePrivilegeEntity x where x.role.id=?";
	private final String _6 = "select x.actions from RolePrivilegeEntity x where x.meunId=? and x.role.id=?";
	private final String _7 = "select x from AccountPrivilegeEntity x where x.account.id=? and x.moduleId=? and x.channelId=?";

	@Autowired
	private ModuleManager moduleManager;
	
	private List<RoleAccountEntity> _getRoleAssign(Long id) {
		return __list(RoleAccountEntity.class, _4, id);
	}
//	
//	@Override
//	public List<ObjectItem> roles(AccountEntity account) {
//		List<RoleEntity> roles = __list(RoleEntity.class, _1);
//		List<Long> sids = __list(Long.class, _3, account.getId());
//		return ObjectCollection.valueOf(roles, sids);
//	}
//	
//	@Override
//	public List<ObjectItem> roles(GroupEntity group) {
//		List<RoleEntity> roles = __list(RoleEntity.class, _1);
//		String ql = "select x.role.id from GroupRoleEntity x where x.invalid=false and x.group.id=?";
//		List<Long> sids = __list(Long.class, ql, group.getId());
//		return ObjectCollection.valueOf(roles, sids);
//	}
//	
//	@Override
//	public void saveGroupRoles(IOperator opt, Long id, Long... roleIds) {
//		String ql = "select x from GroupRoleEntity x where x.group.id=?";
//		List<GroupRoleEntity> oldRoles = __list(GroupRoleEntity.class, ql, id);
//		List<Long> sids = Arrays.asList(roleIds);
//		
//		for(GroupRoleEntity oldRole : oldRoles){
//			oldRole.setInvalid(!sids.remove(oldRole.getId()));
//			entityManager.merge(oldRole);
//		}
//
//		if(!sids.isEmpty()){
//			Date now = new Date();
//			GroupEntity group = entityManager.find(GroupEntity.class, id);
//			for(Long rid : sids){
//				GroupRoleEntity newRole = new GroupRoleEntity();
//				newRole.setGroup(group);
//				newRole.setCreateAt(now);
//				newRole.setCreatorId(opt.getId());
//				newRole.setRole(__get(rid));
//				entityManager.persist(newRole);
//			}
//		}
//	}
//
//	@Override
//	@Transactional
//	public void saveAccountRoles(IOperator opt, Long aid, Long... roleIds) {
//		List<RoleAccountEntity> oldRoles = _getRoleAssign(aid);
//		List<Long> sids = Arrays.asList(roleIds);
//		
//		for(RoleAccountEntity oldRole : oldRoles){
//			oldRole.setInvalid(!sids.remove(oldRole.getId()));
//			entityManager.merge(oldRole);
//		}
//		
//		if(!sids.isEmpty()){
//			Date now = new Date();
//			AccountEntity account = entityManager.find(AccountEntity.class, aid);
//			for(Long rid : sids){
//				RoleAccountEntity newRole = new RoleAccountEntity();
//				newRole.setAccount(account);
//				newRole.setCreateAt(now);
//				newRole.setCreatorId(opt.getId());
//				newRole.setRole(__get(rid));
//				entityManager.persist(newRole);
//			}
//		}
////		if (null != roleIds && roleIds.length > 0) {
////			RoleAccountEntity rae;
////			Date now = new Date();
////			AccountEntity account = entityManager.find(AccountEntity.class, aid);
////			for (Long id : roleIds) {
////				if (roleAssign.isEmpty()) {
////					rae = new RoleAccountEntity();
////					rae.setAccount(account);
////					rae.setCreateAt(now);
////					rae.setCreatorId(opt.getId());
////					rae.setRole(__get(id));
////					entityManager.persist(rae);
////				} else {
////					rae = roleAssign.remove(0);
////					rae.setRole(__get(id));
////					entityManager.merge(rae);
////				}
////			}
////		}
////		for (RoleAccountEntity entity : roleAssign) {
////			entityManager.remove(entity);
////		}
//	}
//	
	@Override
	protected RoleEntity __update(OperateEvent event, RoleEntity entity) throws Exception{
		ModuleDefinition module = moduleManager.module(entity.getModuleKey());
		entity.setModuleName(module.getName());
		RoleEntity re = super.__update(event, entity);
		List<RolePrivilegeEntity> pre = __list(RolePrivilegeEntity.class, _0, re.getId());
		IRoleEditor roleEditor = (IRoleEditor) event.getSource();
		if (null != roleEditor.getPrivileges()) {
			for (String plg : roleEditor.getPrivileges()) {
				if (pre.isEmpty()) {
					readPrivilege(re, plg, event);
				} else {
					RolePrivilegeEntity pe = pre.remove(0);
					if(readPrivilege(pe, plg, event)){
						entityManager.merge(pe);
					}else{
						pre.add(pe);
					}
				}
			}
		}
		for (RolePrivilegeEntity p : pre) {
			entityManager.remove(p);
		}
		return re;
	}

	@Override
	protected RoleEntity __save(OperateEvent event, RoleEntity entity)throws Exception {
		ModuleDefinition module = moduleManager.module(entity.getModuleKey());
		entity.setModuleName(module.getName());
		RoleEntity re = super.__save(event, entity);
		IRoleEditor roleEditor = (IRoleEditor) event.getSource();
		if (null != roleEditor.getPrivileges()) {
			for (String plg : roleEditor.getPrivileges()) {
				readPrivilege(re, plg, event);
			}
		}
		return re;
	}

	private void readPrivilege(RoleEntity re, String name, OperateEvent event) {
		RolePrivilegeEntity pe = new RolePrivilegeEntity();
		if(readPrivilege(pe, name, event)){
			pe.setRole(re);
			entityManager.persist(pe);
		}
	}

	private boolean readPrivilege(RolePrivilegeEntity pe, String name, OperateEvent event) {
		MenuableDefinition menu = moduleManager.item(name);
		pe.setMeunId(name);
		
		if(null != menu){
			pe.setChannelId(menu.getChannel().getId());
			pe.setModuleId(menu.getModule().getId());
			
			long actions = 0;
			String[] values = event.getStringArray(name);
			if (null != values) {
				for (String val : values) {
					actions |= 1 << Long.parseLong(val);
				}
			}
			pe.setActions(actions);
			return true;
		}
		
		TabItemDefinition tabItem = moduleManager.tabItem(name);
		if(null != tabItem){
			TabsDefinition ti = tabItem.getTabs();
			pe.setChannelId(ti.getChannel().getId());
			pe.setModuleId(ti.getModule().getId());
			return true;
		}
		
		return false;
	}

//	@Override
//	public List<String> getPrivilegeMeunId(Long roleId) {
//		return __list(String.class, _5, roleId);
//	}
	
	@Override
	public void rolePrivilege(MenuPrivilegeReader reader, Long... rids) {
		
		String qlids = "";
		int count = 0;
		for(Long rid : rids){
			if(null != rid){
				qlids += "," + rid;
				
				count ++;
			}
		}
		
		if(qlids.isEmpty()) return;
		qlids = qlids.substring(1);
		if(count == 1){
			qlids = "id=" + qlids;
		}else{
			qlids = "id in(" + qlids + ")";
		}
		String ql = "select x.moduleId,x.meunId, x.actions from RolePrivilegeEntity x where x.invalid=false and x.role." + qlids;
		reader.read(__list(Object[].class, ql));
//		
//		for(Object[] obj : __list(Object[].class, ql)){
//			//这里如果有定义操作权限的，需要进行合并
//			String key = (String)obj[0];
//			String mid = (String)obj[1];
//			Number value = (Number)obj[2];
//			Number actions = privilegeMapped.get(mid);
//			if(null != actions){
//				value = actions.longValue() | value.longValue();
//			}
//			privilegeMapped.put(mid, value);
//			if(!modules.contains(key)) modules.add(key);
//		}
	}
	
//	private void internalReadPrivilege(MenuPrivilegeReader reader, List<Object[]> items){
//		for(Object[] obj : items){
//			//这里如果有定义操作权限的，需要进行合并
//			String key = (String)obj[0];
//			String mid = (String)obj[1];
//			Number value = (Number)obj[2];
//			Number actions = privilegeMapped.get(mid);
//			if(null != actions){
//				value = actions.longValue() | value.longValue();
//			}
//			privilegeMapped.put(mid, value);
//			if(null != modules && !modules.contains(key)) modules.add(key);
//		}
//	}
	
	@SuppressWarnings("unchecked")
	private void internalReadPrivilege(MenuPrivilegeReader reader, String sql){
		reader.read(entityManager.createNativeQuery(sql).getResultList());
	}
	
	@Override
	public void accountPrivilege(MenuPrivilegeReader reader, Long aid) {
		// TODO Auto-generated method stub
		if(null == aid) return;
		
		String ql = "select x.C_MODULEID,x.C_MENUID,x.C_ACTIONS ";
		ql += "from t_roleassign r,t_privilege x,t_role y ";
		ql += "where x.C_INVALID=0 and x.R_ROLE_ID=y.C_ID and r.R_ROLE_ID=y.C_ID ";
		ql += "  and y.C_STATUS=1 and y.C_DELETED=0 ";
		ql += "  and r.C_INVALID=0 and r.R_ACCOUNT_ID=" + aid;
		internalReadPrivilege(reader, ql);
		
		ql = "select x.C_MODULEID,x.C_MENUID,x.C_ACTIONS ";
		ql += "from t_privilege x ";
		ql += "where x.C_INVALID=0 and x.R_ACCOUNT_ID=" + aid;
		internalReadPrivilege(reader, ql);
		
		ql = "select x.C_MODULEID,x.C_MENUID,x.C_ACTIONS ";
		ql += "from t_privilege x,t_role y,t_group z,t_groupr g,t_groupa a ";
		ql += "where x.R_ROLE_ID=y.C_ID and g.R_ROLE_ID=y.C_ID ";
		ql += "  and g.R_GROUP_ID=z.C_ID and a.R_GROUP_ID=z.C_ID";
		ql += "  and y.C_STATUS=1 and y.C_DELETED=0 ";
		ql += "  and z.C_STATUS=1 and z.C_DELETED=0 ";
		ql += "  and x.C_INVALID=0 and g.C_INVALID=0 and a.C_INVALID=0 ";
		ql += "  and a.R_ACCOUNT_ID=" + aid;
		internalReadPrivilege(reader, ql);
	}

//	@Override
//	public long getActions(String meunId, Long roleId) {
//		if(null != roleId && roleId > 0){
//			Long as = __first(Long.class, _6, meunId, roleId);
//			if(null != as) return as;
//		}
//		return 0L;
//	}

	@Override
	@Transactional
	public void saveAdminPrivilege(IOperator opt, Long aid, String moduleId, String channelId, String... menuIds) {
		List<AccountPrivilegeEntity> aps = __list(AccountPrivilegeEntity.class, _7, aid, moduleId, channelId);
		if (null != menuIds && menuIds.length > 0) {
			for (String menuId : menuIds) {
				if (aps.isEmpty()) {
					AccountPrivilegeEntity entity = new AccountPrivilegeEntity();
					entity.setAccount(entityManager.find(AccountEntity.class, aid));
					entity.setChannelId(channelId);
					entity.setMeunId(menuId);
					entity.setModuleId(moduleId);
					entityManager.persist(entity);
				} else {
					AccountPrivilegeEntity entity = aps.remove(0);
					entity.setChannelId(channelId);
					entity.setMeunId(menuId);
					entity.setModuleId(moduleId);
					entityManager.merge(entity);
				}
			}
		}
		
		for (AccountPrivilegeEntity entity : aps) {
			entityManager.remove(entity);
		}
	}

	@Override
	public List<RoleEntity> getRoles(Long accountId) {
		return __list(RoleEntity.class, _1_1, accountId);
	}

	@Override
	public List<AccountPrivilegeEntity> getAccountPrivilege(Long accountId, String moduleId, String channelId) {
		return __list(AccountPrivilegeEntity.class, _7, accountId, moduleId, channelId);
	}
	@Override
	public List<RoleEntity> moduleRoles(IOperator opt, String moduleKey) {
		String ql = "select x from RoleEntity x where x.deleted=false and x.moduleKey=?";
		return __list(RoleEntity.class, ql, moduleKey);
	}
}
